import StringUtil from '../utils/StringUtil'
import { redis } from '../loaders/loader-redies'
import koaJwt from 'koa-jwt'
import jwt from 'jwt-simple'
import { EXPIRES } from '../config/index'
/**
 * 权限校验中间件
 */
module.exports.permission = ({ secret }) => {
    return async(ctx, next) => {
        let token = null
        ctx.jwtSession = {}
        let code = 401
        let message = ''
        let auth = ctx.header.authorization // `Bearer ${token}`
        if (auth !== undefined) {
            try {
                ctx.jwtSession = jwt.decode(auth.split(' ')[1], secret);
                const isAdmin = ctx.jwtSession.isAdmin
                    // 判断APIS访问权限
                let method = ctx.request.method
                let url = ctx.request.url.split('?')[0]
                let authed = false
                    // 判断API是否需要授权NO_
                let gVarName = `AUTH_REQUIRED_APIS`
                    // 判断该API用户是否需要授权
                if (global[gVarName].indexOf(`|${method}_${url}|`) > -1) {
                    // 如果该api需要授权，判断用户是否授权超时
                    let userExpireSession = await redis.timeToExpire(`user_expire_${ctx.jwtSession.userId}`);
                    if (userExpireSession < 0) {
                        message = '授权已过期，请重新登录'
                        code = 401
                        authed = false
                    } else {
                        // 如果用户授权未超时，判断用户是否有api权限
                        let apisStr = await redis.getString(`PERMISSION_APIS_${ctx.jwtSession.userId}`) // 备注：该redis缓存在用户获取用户信息后加载
                        if (apisStr && apisStr.indexOf(`|${method}_${url}|`) > -1) {
                            authed = true
                        } else {
                            code = 1002
                            message = '功能没有权限'
                            console.log(`该api没有权限${ url}`.red);
                        }
                    }
                } else {
                    authed = true
                }
                if (!authed) {
                    ctx.body = {
                        code,
                        message
                    }
                    return;
                }
                // 每次请求都延长token过期时间
                if (ctx.jwtSession && isAdmin)
                    await redis.expire(`user_expire_${ctx.jwtSession.userId}`, 60 * 60 * 12)
            } catch (e) {
                console.log('e', e);
                ctx.status = 401
            }
        }

        // 设置Session
        ctx.setJwtSession = (data, expires) => {
            ctx.jwtSession = Object.assign(data, {
                    id: ctx.jwtSession.id,
                    exp: Date.now() + EXPIRES * 1000
                })
                // 判断SessionId是否存在
            if (ctx.jwtSession.id === undefined || ctx.jwtSession.id === null) {
                ctx.jwtSession.id = StringUtil.createSessionId()
            }
            let id = data.userId || ctx.jwtSession.id
            redis.set(`user_expire_${id}`, true)
            redis.expire(`user_expire_${id}`, expires)
            token = jwt.encode(ctx.jwtSession, secret);
            return token;
        }

        // 清除Session
        ctx.removeJwtSession = () => {
            token = jwt.encode({}, secret)
        }

        // 检查授权的后台权限
        ctx.checkAuth = async(authCode) => {
            let authsStr = await redis.getString(`PERMISSION_AUTHS_${ctx.jwtSession.admin.id}`)
            if (authsStr.indexOf(`|${authCode}|`) > -1) {
                return true
            }
            return false
        }

        let unauthorizedResult = {
            code: 2,
            message: '认证授权失败或者授权已超时'
        }
        await next().catch((err) => {
            console.log('err', err);

            if (err.status === 401) {
                ctx.status = 401
                ctx.body = unauthorizedResult
            } else {
                throw err
            }
        })
        if (ctx.status === 401) {
            ctx.body = unauthorizedResult
            return
        }
    }
}

module.exports.unless = ({ secret, path = [] }) => {
    return koaJwt({ secret }).unless({
        path: path // [/^\/login/]
    })
}